#include "parser.h"
#include <iostream>
#include "DeclAST.h"
#include "Globe.h"
parser::parser()
{
    this->lexer = nullptr;
}

parser::parser(LEX* lex)
{
    this->lexer = lex;
}

unique_ptr<BaseAST> parser::parseStatement()
{

    unique_ptr<BaseAST>expr;
    switch (this->lexer->next_token())
    {
    case TOK::SCANEOF:
        expr.reset(new FullAST);
        break;
    case TOK::K_INT:
    case TOK::K_CONST:
        expr = this->parseDecl();
        expr->Dump();
        std::cout << std::endl;
        break;
    default:
        expr = this->parseExp();
        this->lexer->match(TOK::SEMICOLON);
        expr->Dump();
        std::cout << std::endl;
        break;
    }
    expr->Analyze();
    return expr;
}

std::pair<std::string, unique_ptr<BaseExpAST>> parser::parseVarDef(bool constDecl)
{
    string valName = this->lexer->get_buffer();
    this->lexer->match(TOK::IDENTIFIER);
    unique_ptr<BaseExpAST>exp;
    bool suc = CurrentValMgr->Alloc(valName, constDecl == 0);
    if (!suc)
    {
        std::cerr << "redefinition; multiple initialization" << std::endl;
        exit(-1);
    }
    if (this->lexer->next_token() == TOK::ASSIGN)
    {
        this->lexer->match(TOK::ASSIGN);
        exp = this->parseExp();
    }
    else if (constDecl)
    {
        std::cerr << "const object must be initialized" << std::endl;
        exit(-1);
    }
    return std::make_pair(valName, std::move(exp));
}

unique_ptr<BaseAST> parser::parseDecl()
{
    unique_ptr<DeclAST> ret(new DeclAST);
    bool constDecl = false;
    if (this->lexer->next_token() == TOK::K_CONST)
    {
        constDecl = true;
        this->lexer->match(TOK::K_CONST);
    }
    switch (this->lexer->next_token())
    {
    case TOK::K_INT:this->lexer->match(TOK::K_INT); break;
    default:
        std::cerr << "unexpected token" << std::endl;
        exit(-1);
    }
    ret->constDecl = constDecl;
    ret->decl.insert(this->parseVarDef(ret->constDecl));
    while (this->lexer->next_token() == TOK::COMMA)
    {
        this->lexer->match(TOK::COMMA);
        ret->decl.insert(this->parseVarDef(ret->constDecl));
    }
    this->lexer->match(TOK::SEMICOLON);
    return ret;
}
